package com.ecoolex.ying.space.core.manager;

import com.alibaba.fastjson.JSON;
import com.ecoolex.framework.common.enums.ResultCode;
import com.ecoolex.framework.common.pojo.Page;
import com.ecoolex.framework.common.pojo.Pagination;
import com.ecoolex.framework.common.pojo.Sorting;
import com.ecoolex.framework.common.pojo.Sortings;
import com.ecoolex.framework.common.util.BizAssert;
import com.ecoolex.framework.common.util.Check;
import com.ecoolex.ying.space.core.dao.PickGoodsDAO;
import com.ecoolex.ying.space.core.service.PickGoodsSearchService;
import com.ecoolex.ying.space.entity.*;
import com.ecoolex.ying.space.entity.PickGoodsWithBLOBs.Column;
import com.ecoolex.ying.space.enums.PickGoodsStatus;
import com.ecoolex.ying.space.pojo.EditPickGoodsDTO;
import com.ecoolex.ying.space.pojo.PickGoodsParametersDTO;
import com.ecoolex.ying.space.pojo.QueryPickGoodsDTO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.Instant;
import java.util.Date;
import java.util.List;

import static com.ecoolex.ying.space.entity.PickGoods.IS_DELETED;
import static com.ecoolex.ying.space.entity.PickGoods.NOT_DELETED;

@Service
public class PickGoodsManager {

    @Autowired
    private PickGoodsDAO dao;
    @Autowired
    private PickGoodsLabelAssociateManager pickGoodsLabelAssociateManager;
    @Autowired
    private PickGoodsChannelManager pickGoodsChannelManager;
    @Autowired
    private PickGoodsProductManager pickGoodsProductManager;
    @Autowired
    private DesignerProjectItemsProductManager designerProjectItemsProductManager;
    @Autowired
    private DesignerProjectItemsProductCustomManager designerProjectItemsProductCustomManager;
    @Autowired
    private GoodsManager goodsManager;
    @Autowired
    private GoodsClassifyManager goodsClassifyManager;

    @Autowired
    private PickGoodsSearchService pickGoodsSearchService;

    public long countByClassifyId(Integer classifyId) {
        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria().andClassifyIdEqualTo(classifyId).andDeletedEqualTo(NOT_DELETED);
        return dao.countByExample(example);
    }

    public long countByGoodsId(Integer goodsId) {
        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria().andGoodsIdEqualTo(goodsId).andDeletedEqualTo(NOT_DELETED);
        return dao.countByExample(example);
    }

    private void verify(EditPickGoodsDTO record) {
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getName()), ResultCode.VERIFY.build(10), "优选商品名称不能为空");
        if (Check.notNull(record.getClassifyId())) {
            GoodsClassify classify = goodsClassifyManager.getById(record.getClassifyId());
            BizAssert.isTrue(Check.notNull(classify), ResultCode.VERIFY.build(11), "商品分类不存在");
            BizAssert.isTrue(classify.getLevel() == 2, ResultCode.VERIFY.build(12), "不能关联{}级分类商品分类", classify.getLevel());
        }
    }

    @Transactional
    public PickGoodsWithBLOBs create(Integer goodsId, EditPickGoodsDTO add, String createUser) {
        verify(add);

        PickGoodsWithBLOBs record = new PickGoodsWithBLOBs();
        record.setGoodsId(goodsId);
        record.setName(add.getName());
        record.setClassifyId(add.getClassifyId());
        record.setLabelIds(Check.isNull(add.getLabelIds()) ? null : JSON.toJSONString(add.getLabelIds()));
        record.setCoded(add.getCoded());
        record.setCounterPrice(add.getCounterPrice());
        record.setRetailPrice(add.getRetailPrice());
        record.setCurrencyType(add.getCurrencyType());
        record.setImage(add.getImage());
        record.setShopwindowImages(Check.isNull(add.getShopwindowImages()) ? null : JSON.toJSONString(add.getShopwindowImages()));
        record.setDetail(add.getDetail());
        record.setParameters(Check.isNull(add.getParameters()) ? null : JSON.toJSONString(add.getParameters()));
        record.setSource(add.getSource());
        record.setStatus(PickGoodsStatus.OFFLINE.real());
        record.setDeleted(NOT_DELETED);
        record.setCreateUser(createUser);
        record.setCreateTime(Date.from(Instant.now()));
        record.setUpdateUser(createUser);
        record.setUpdateTime(Date.from(Instant.now()));
        dao.insert(record);

        pickGoodsLabelAssociateManager.refresh(record, createUser);

        // 创建索引
        pickGoodsSearchService.create(record.getPickGoodsId());

        return record;
    }

    @Transactional
    public void update(Integer pickGoodsId, EditPickGoodsDTO edit, String updateUser) {
        verify(edit);

        PickGoodsWithBLOBs record = getById(pickGoodsId);
        BizAssert.isTrue(Check.notNull(record), ResultCode.VERIFY.build(11), "优选商品为空");

        record.setPickGoodsId(pickGoodsId);
        record.setName(edit.getName());
        record.setClassifyId(edit.getClassifyId());
        record.setLabelIds(Check.isNull(edit.getLabelIds()) ? null : JSON.toJSONString(edit.getLabelIds()));
        record.setCoded(edit.getCoded());
        record.setCounterPrice(edit.getCounterPrice());
        record.setRetailPrice(edit.getRetailPrice());
        record.setCurrencyType(edit.getCurrencyType());
        record.setImage(edit.getImage());
        record.setShopwindowImages(Check.isNull(edit.getShopwindowImages()) ? null : JSON.toJSONString(edit.getShopwindowImages()));
        record.setDetail(edit.getDetail());
        record.setParameters(Check.isNull(edit.getParameters()) ? null : JSON.toJSONString(edit.getParameters()));
        record.setSource(edit.getSource());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        // 如果是上线状态, 需要检查参数
        if (PickGoodsStatus.ONLINE.equal(record.getStatus())) {
            verifyGoodsOnline(record);
        }

        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria().andPickGoodsIdEqualTo(pickGoodsId).andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record,
                example,
                Column.name,
                Column.classifyId,
                Column.labelIds,
                Column.coded,
                Column.counterPrice,
                Column.retailPrice,
                Column.image,
                Column.shopwindowImages,
                Column.detail,
                Column.parameters,
                Column.source,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "更新优选商品属性失败");

        pickGoodsLabelAssociateManager.refresh(record, updateUser);
        // 更新索引
        pickGoodsSearchService.update(record.getPickGoodsId());
    }

    @Transactional
    public void delete(PickGoodsWithBLOBs record, String updateUser) {
        BizAssert.isTrue(PickGoodsStatus.canDel(record), "非下线状态无法删除");

        record.setDeleted(IS_DELETED);
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria()
                .andPickGoodsIdEqualTo(record.getPickGoodsId())
                .andStatusEqualTo(record.getStatus())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.deleted,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "删除失败");

        dao.updateByPrimaryKeySelective(record,
                Column.deleted,
                Column.updateUser,
                Column.updateTime);

        // 删除标签
        pickGoodsLabelAssociateManager.deleteByPickGoodsId(record.getPickGoodsId(), updateUser);
        // 删除渠道
        pickGoodsChannelManager.deleteByPickGoodsId(record.getPickGoodsId(), updateUser);
        // 删除产品
        pickGoodsProductManager.deleteByPickGoodsId(record.getPickGoodsId(), updateUser);
        // 删除设计师项目数据
        designerProjectItemsProductManager.deleteByPickGoodsId(record.getPickGoodsId(), updateUser);
        designerProjectItemsProductCustomManager.deleteByPickGoodsId(record.getPickGoodsId(), updateUser);
        // 删除索引
        pickGoodsSearchService.delete(record.getPickGoodsId());
    }

    private void verifyGoodsOnline(PickGoodsWithBLOBs record) {
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getName()), ResultCode.VERIFY.build(20), "产品名称不能为空");

        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getParameters()), ResultCode.VERIFY.build(21), "产品属性不能为空");
        PickGoodsParametersDTO parameters = JSON.parseObject(record.getParameters(), PickGoodsParametersDTO.class);
//        BizAssert.isTrue(Check.notNullOrTrimEmpty(parameters.getSubTitle()), ResultCode.VERIFY.build(22), "副标题不能为空");
        BizAssert.isTrue(Check.notNullOrTrimEmpty(parameters.getTexture()), ResultCode.VERIFY.build(23), "材质不能为空");
        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getImage()), ResultCode.VERIFY.build(24), "图片不能为空");
        BizAssert.isTrue(Check.notNullOrEmpty(JSON.parseArray(record.getShopwindowImages(), String.class)), ResultCode.VERIFY.build(25), "橱窗图片不能为空");
        BizAssert.isTrue(Check.notNull(record.getClassifyId()), ResultCode.VERIFY.build(26), "商品类型不能为空");
//        BizAssert.isTrue(Check.notNull(record.getRetailPrice()), ResultCode.VERIFY.build(27), "商品零售价格不能为空");
//        BizAssert.isTrue(Check.notNullOrTrimEmpty(record.getDetail()), ResultCode.VERIFY.build(28), "商品详情不能为空");

        Goods goods = goodsManager.getById(record.getGoodsId());
        BizAssert.isTrue(Check.notNull(goods), ResultCode.VERIFY.build(29), "商品不能为空");
    }

    void verifyProductOnline(Integer pickGoodsId) {
        PickGoods goods = getById(pickGoodsId);
        if (PickGoodsStatus.ONLINE.equal(goods.getStatus())) {
            verifyProductOnline(goods);
        }
    }

    void verifyProductOnline(PickGoods record) {
        List<PickGoodsProduct> productList = pickGoodsProductManager.queryByPickGoodsId(record.getPickGoodsId());

        BizAssert.isTrue(Check.notNullOrEmpty(productList), ResultCode.VERIFY.build(30), "产品为空");
        productList.forEach(product -> {
            BizAssert.isTrue(Check.notNull(product.getRetailPrice()), ResultCode.VERIFY.build(31), "产品零售价格为空");
        });
    }


    public void online(PickGoodsWithBLOBs record, String updateUser) {
        BizAssert.isTrue(PickGoodsStatus.canOnline(record), "状态不合法, 无法上线");

        // 上线检查
        verifyGoodsOnline(record);
        verifyProductOnline(record);

        record.setStatus(PickGoodsStatus.ONLINE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria()
                .andPickGoodsIdEqualTo(record.getPickGoodsId())
                .andStatusEqualTo(PickGoodsStatus.OFFLINE.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.status,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "上线失败");
        // 刷新索引
        pickGoodsSearchService.update(record.getPickGoodsId());
    }

    public void offline(PickGoodsWithBLOBs record, String updateUser) {
        BizAssert.isTrue(PickGoodsStatus.canOffline(record), "状态不合法, 无法下线");

        record.setStatus(PickGoodsStatus.OFFLINE.real());
        record.setUpdateUser(updateUser);
        record.setUpdateTime(Date.from(Instant.now()));

        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria()
                .andPickGoodsIdEqualTo(record.getPickGoodsId())
                .andStatusEqualTo(PickGoodsStatus.ONLINE.real())
                .andDeletedEqualTo(NOT_DELETED);

        int row = dao.updateByExampleSelective(record, example,
                Column.status,
                Column.updateUser,
                Column.updateTime);

        BizAssert.isTrue(row == 1, "下线失败");
        // 刷新索引
        pickGoodsSearchService.update(record.getPickGoodsId());
    }

    void refreshProductPrice(Integer pickGoodsId) {
        dao.refreshProductPrice(pickGoodsId);
    }

    public PickGoodsWithBLOBs getById(Integer pickGoodsId) {
        return dao.selectByPrimaryKeyWithLogicalDelete(pickGoodsId, NOT_DELETED);
    }

    public Pagination<PickGoodsWithBLOBs> query(QueryPickGoodsDTO query, Sorting[] sorts, Page page) {
        PickGoodsExample example = new PickGoodsExample();
        PickGoodsExample.Criteria criteria = example.createCriteria();

        if (Check.notNullOrTrimEmpty(query.getName())) {
            criteria.andNameLike('%' + query.getName() + '%');
        }
        criteria.andDeletedEqualTo(NOT_DELETED);

        example.orderBy(Sortings.builder(sorts).verify(GoodsWithBLOBs.Column::valueOf).toSql());
        example.setOffset(page.getFirstIndex());
        example.setRows(page.getPageSize());

        return Pagination.create(page, dao.countByExample(example), () -> dao.selectByExampleWithBLOBs(example));
    }

    public Pagination<PickGoodsWithBLOBs> queryByUserFavorite(Integer userId, String keyword, Page page) {
        String newkeyword = Check.isNullOrTrimEmpty(keyword) ? null : '%' + keyword + '%';

        return Pagination.create(page, dao.countByUserFavorite(userId, newkeyword), () -> dao.queryByUserFavorite(userId, newkeyword, page));
    }

    public List<PickGoodsWithBLOBs> queryByPickGoodsIds(List<Integer> pickGoodsIdList) {
        PickGoodsExample example = new PickGoodsExample();
        example.createCriteria()
                .andPickGoodsIdIn(pickGoodsIdList)
                .andDeletedEqualTo(NOT_DELETED);
        return dao.selectByExampleWithBLOBs(example);
    }
}